package com.saftalk;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.blobstore.BlobInfo;
import com.google.appengine.api.blobstore.BlobInfoFactory;
import com.google.appengine.api.blobstore.BlobKey;
import com.google.appengine.api.blobstore.BlobstoreService;
import com.google.appengine.api.blobstore.BlobstoreServiceFactory;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.images.Image;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.images.ImagesServiceFactory;
import com.google.appengine.api.images.Transform;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.saftalk.db.PMF;
import com.saftalk.db.entity.User;
import com.saftalk.db.entity.photo.FamilyPhoto;
import com.saftalk.ui.UIMessageResult;
import com.saftalk.ui.UIPhotoResult;
import com.saftalk.ui.UIUserResult;

public class ImageServlet extends BaseServlet {

	private static final long serialVersionUID = 5643448910926575410L;
	

	@SuppressWarnings("unchecked")
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		GsonBuilder builder = new GsonBuilder();
		Gson gson = builder.create();
		resp.setContentType("application/json");
		resp.setCharacterEncoding("UTF-8");
		
		if("/family/url".equals(req.getPathInfo())) {
			
			gson.toJson(new UIMessageResult(true, BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/image/family")), resp.getWriter());
			
		} else if ("/user/url".equals(req.getPathInfo())) { 
			
			gson.toJson(new UIMessageResult(true, BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/image/user")), resp.getWriter());
			
		} else if ("/family".equals(req.getPathInfo())) {

			PersistenceManager pm = PMF.get().getPersistenceManager();
			UIUserResult user = (UIUserResult) req.getSession().getAttribute("user");
			if (user == null) {
				gson.toJson(new UIMessageResult(false, "Must be logged in!"),
						resp.getWriter());
				return;
			}
			Long familyId = user.getFamilyId();
			Query q = pm.newQuery(FamilyPhoto.class);
			List<FamilyPhoto> results = null;
			try {
				q.setFilter("familyId == idParam");
				q.declareParameters("Long idParam");
				results = (List<FamilyPhoto>) q.execute(familyId);
			} catch (Exception e) {
				e.printStackTrace();
				gson.toJson(new UIMessageResult(false, "Failed to get family photos"),
						resp.getWriter());
			} finally {
				q.closeAll();
			}
			
			
			if (results == null || results.size() == 0) {
				/*gson.toJson(new UIMessageResult(true, "No photos for family"),
						resp.getWriter());*/
				/* we just leave the data empty */
			}
			
			gson.toJson(convertResults(results), resp.getWriter());			
			
		} else if ("/thumb".equals(req.getPathInfo())) {
			
			if (req.getParameter("key") == null || req.getParameter("key").length() == 0) {
				//FIXME: Should return a PROPER IMAGE
				gson.toJson(new UIMessageResult(false, "Missing key parameter"), resp.getWriter());
				return;
			}
			BlobKey blobKey = new BlobKey(req.getParameter("key"));
			
			DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
			BlobInfoFactory infoFactory = new BlobInfoFactory(ds);
			BlobInfo info = infoFactory.loadBlobInfo(blobKey);
			
			if (info == null) {
				//FIXME: Should return a PROPER IMAGE
				gson.toJson(new UIMessageResult(false, "No such image for key"), resp.getWriter());
				return;
			}			
			
			
	        ImagesService imagesService = ImagesServiceFactory.getImagesService();
	        Image oldImage = ImagesServiceFactory.makeImageFromBlob(blobKey);
	        // int oldHeight = oldImage.getHeight();
	        //int oldWidth = oldImage.getWidth();
	        Transform resize = ImagesServiceFactory.makeResize(100, 100, 0.5, 0.5);				
	        
	        Image newImage = imagesService.applyTransform(resize, oldImage);
	        
	        //BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService();
	        resp.setContentType(info.getContentType());
	        
	        resp.getOutputStream().write(newImage.getImageData());



		} else {
				if (req.getParameter("key") == null || req.getParameter("key").length() == 0) {
					//FIXME: Should return a PROPER IMAGE
					gson.toJson(new UIMessageResult(false, "Missing key parameter"), resp.getWriter());
					return;
				}

			  BlobKey blobKey = new BlobKey(req.getParameter("key"));
			  BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService();
		      bs.serve(blobKey, resp);
		}	      

	}
	
	@SuppressWarnings("unchecked")
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("application/json; charset=UTF-8");

		GsonBuilder builder = new GsonBuilder();
		Gson gson = builder.create();
		PersistenceManager pm = PMF.get().getPersistenceManager();
		BlobstoreService bs = BlobstoreServiceFactory.getBlobstoreService(); 
		Map<String, List<BlobKey>> blobs = bs.getUploads(req);
		BlobKey blobKey = blobs.get("file").get(0);
		
		

		if ("/user".equals(req.getPathInfo())) {
			
			UIUserResult sessionUser = (UIUserResult) req.getSession().getAttribute("user");
			
			
			
			Long userId;
			try {
				if (req.getParameter("userId") == null) {
					throw new Exception();
				}
				userId = Long.parseLong(req.getParameter("userId"));
			} catch (Exception e) {
				gson.toJson(new UIMessageResult(false, "Failed to parse parameter or missing parameter"),
						resp.getWriter());
				return;
			} 
			
			if ((sessionUser==null) || ( !sessionUser.isAdmin() && !sessionUser.getUserId().equals(userId))) {
				gson.toJson(new UIMessageResult(false, "Not authorized"),
						resp.getWriter());
				return;
			}
			
			Query q = pm.newQuery(User.class);
			List<User> results = null;
			try {
				
				q.setFilter("id == idParam");
				q.declareParameters("Integer idParam");
				results = (List<User>) q.execute(userId);
				
			} catch (Exception e) {
				e.printStackTrace();
				gson.toJson(new UIMessageResult(false, "Failed to get users"),
						resp.getWriter());
			} finally {
				q.closeAll();
			}
			
			
			if (results == null || results.size() == 0) {
				gson.toJson(new UIMessageResult(false, "No such users"),
						resp.getWriter());			
			}
			User user = results.get(0);
			if (user.getPhotoId() != null && user.getPhotoId().length() > 0 && !user.getPhotoId().equals("none")) { 
				//THE "NONE" is legacy code unfortunately
				bs.delete(new BlobKey(user.getPhotoId())); // removes old user photo!	
			}
			user.setPhotoId(blobKey.getKeyString());
			
			try {
				pm.makePersistent(user);
			} finally {
				pm.close();
			}
			
			
			//TODO: wrap this!!
			cache.remove(sessionUser.getFamilyId());
			gson.toJson(new UIMessageResult(true, "Photo added for: " + user.getName() + " to view go to: /image/serve?key=" + blobKey.getKeyString()),
					resp.getWriter());
			
			
		} else if ("/family".equals(req.getPathInfo())) {
			
			UIUserResult user = (UIUserResult) req.getSession().getAttribute("user");
			if (user == null) {
				gson.toJson(new UIMessageResult(false, "Not logged in!"),
						resp.getWriter());				
			}
			String desc = req.getParameter("description");
			
			Long familyId = user.getFamilyId();
			FamilyPhoto familyPhoto = null;
			try {
				
				familyPhoto = new FamilyPhoto(blobKey.getKeyString(), familyId, desc);
				pm.makePersistent(familyPhoto);
				
			} catch (Exception e) {
				e.printStackTrace();
				gson.toJson(new UIMessageResult(false, "Failed to upload family photo"),
						resp.getWriter());
				return;
			} finally {
				pm.close();
			}
			
			gson.toJson(new UIPhotoResult(familyPhoto), resp.getWriter());
		}
		
	}
	
	private List<UIPhotoResult> convertResults(List<FamilyPhoto> photos) {
		
		List<UIPhotoResult> uiList = new ArrayList<UIPhotoResult>();
		for (FamilyPhoto photo: photos) {
			uiList.add(new UIPhotoResult(photo));
		}
		return uiList;
	}
	
	

}
